#ifndef __TINY_TEST__

#include "vbb_METER.h"
#include "vbb_Header.h"
#include "vbb_FLASHMEM.h"
#include "vbb_Storage.h"
#include "fw/vbb_RTC.h"
#include "vbb_SAVE.h"
#include "vbb_FirmwareUtils.h"
#include <stdio.h>
#include <string.h>
#include "vbb_SAVE.h"

extern VBB_Storage storage;
extern VBB_FlashMem flashMem;
extern VBB_RTC rtc;

int on_date[3];
int on_time[3];

int off_date[3];
int off_time[3];

VBB_METER meter;

extern bool cab_occupied;
unsigned int free_PulseCount;
unsigned int busy_PulseCount;
unsigned int last_PulseCollected;
unsigned int cab_on_time;
unsigned int cab_off_time;
unsigned int LastSendSecondlyMessage;

void vbb_METER_Init(void)
{      
    if (vbb_DeviceModel() == CNS03)        
        vbb_USART_Init(&(meter.usart_meter), UART4, 19200, 2, meter.buffer, 8192);
    else if (vbb_DeviceModel() == CNS01 || vbb_DeviceModel() == BA01)
        vbb_USART_Init(&(meter.usart_meter), UART4, 19200, 2, meter.buffer, 8192);
    
    vbb_Message_Init(&(meter.message));
    vbb_Message_Init(&(meter.last_message));    
    
    free_PulseCount = vbb_BACKUP_GetInt(SAVE_METER_FREE_PULSE);
    busy_PulseCount = vbb_BACKUP_GetInt(SAVE_METER_BUSY_PULSE);    

    last_PulseCollected = vbb_BACKUP_GetInt(SAVE_COLLECTED_PULSE);
    cab_on_time = vbb_BACKUP_GetInt(SAVE_METER_CAB_ON_TIME);
    if (cab_on_time != 0)
        cab_occupied = TRUE;
    else
        cab_occupied = FALSE;
    LastSendSecondlyMessage = 0;    
}

int remainLength = 0;
unsigned char _checksum = 0;
unsigned char _curMsg;

bool meter_TC_detected = FALSE;
bool meter_HP_detected = FALSE;

void METER_AddToMessage(char c)
{
    uint8_t hbyte;
    uint8_t lbyte;
    
    hbyte = c & 0x0F;
    lbyte = (c >> 4) & 0x0F;
    
    if (lbyte < 10)
        vbb_Message_AddByte(&(meter.message), '0' + lbyte);                
    else
        vbb_Message_AddByte(&(meter.message), 'A' + (lbyte - 10));
            
    if (hbyte < 10)
        vbb_Message_AddByte(&(meter.message), '0' + hbyte);                
    else
        vbb_Message_AddByte(&(meter.message), 'A' + (hbyte - 10));
}

unsigned int deltaPulse;
extern VBB_Sensor sensor;

void METER_OnTaxiTrip(void)
{
    if (cab_occupied == TRUE)
    {
        cab_occupied = FALSE;
        cab_off_time = vbb_RTC_GetCurrSec();                                                                        
        //Generate message when the taxi trip is finished                        
        vbb_RTC_Convert(cab_on_time, on_time, on_date);
        vbb_RTC_Convert(cab_off_time, off_time, off_date);                                                
        
        vbb_FLASHMEM_PushMessageF("$EMU,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,%d,%02d%02d%02d,%02d%02d%02d,%02d%02d%02d,%02d%02d%02d,%u,%u,0,0,0,0,0",
            VERSION,
            storage.config.OwnerId,
            storage.config.VehicleId,                            
            rtc.hour,
            rtc.minute,
            rtc.second,
            rtc.day,                
            rtc.month,
            rtc.year % 100,
            cab_occupied,
            on_time[0],
            on_time[1],
            on_time[2],
            on_date[0],
            on_date[1],
            on_date[2] % 100,
            off_time[0],
            off_time[1],
            off_time[2],
            off_date[0],
            off_date[1],
            off_date[2] % 100,
            free_PulseCount,
            busy_PulseCount);
        cab_on_time = 0;
    }
}

void METER_OffTaxiTrip(void)
{
    if (cab_occupied == FALSE)
    {
        cab_occupied = TRUE;
        cab_on_time = vbb_RTC_GetCurrSec();
        cab_off_time = 0;
        
        vbb_RTC_Convert(cab_on_time, on_time, on_date);                        
        
        //Generate message when taxi trip is started
        vbb_FLASHMEM_PushMessageF("$EMU,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,%d,%02d%02d%02d,%02d%02d%02d,%02d%02d%02d,%02d%02d%02d,%u,%u,0,0,0,0,0",
            VERSION,
            storage.config.OwnerId,
            storage.config.VehicleId,                            
            rtc.hour,
            rtc.minute,
            rtc.second,
            rtc.day,                
            rtc.month,
            rtc.year % 100,
            cab_occupied,
            on_time[0],
            on_time[1],
            on_time[2],
            on_date[0],
            on_date[1],
            on_date[2] % 100,
            on_time[0],
            on_time[1],
            on_time[2],
            on_date[0],
            on_date[1],
            on_date[2] % 100,
            free_PulseCount,
            busy_PulseCount);
        LastSendSecondlyMessage = vbb_RTC_GetSec();
    }                    
    
    if (vbb_RTC_GetSec() - LastSendSecondlyMessage >= 30)
    {                        
        vbb_RTC_Convert(cab_on_time, on_time, on_date);                        
        
        //Generate messages during a taxi trip
        vbb_FLASHMEM_PushMessageF("$EMU,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,%d,%02d%02d%02d,%02d%02d%02d,%02d%02d%02d,%02d%02d%02d,%u,%u,0,0,0,0,0",
            VERSION,
            storage.config.OwnerId,
            storage.config.VehicleId,                            
            rtc.hour,
            rtc.minute,
            rtc.second,
            rtc.day,                
            rtc.month,
            rtc.year % 100,
            cab_occupied,
            on_time[0],
            on_time[1],
            on_time[2],
            on_date[0],
            on_date[1],
            on_date[2] % 100,
            on_time[0],
            on_time[1],
            on_time[2],
            on_date[0],
            on_date[1],
            on_date[2] % 100,
            free_PulseCount,
            busy_PulseCount);
        LastSendSecondlyMessage = vbb_RTC_GetSec();
    }
}

unsigned int LastSyncClock;

char syncClockStr[64];

void METER_PushSyncClock()
{
    unsigned char check_sum = 0;
    int i = 0;
    int len = 0;
    unsigned char lbyte, hbyte;
    
    if (rtc.year > 2000)
    {
        sprintf(syncClockStr, "TC,T,2,%02X%02X%02X%02X%02X%02X", (rtc.year % 100), rtc.month, rtc.day, rtc.hour, rtc.minute, rtc.second);
        len = strlen(syncClockStr);
        for (i = 0; i < len; i++)
            check_sum += syncClockStr[i];
        
        lbyte = check_sum & 0x0F;
        hbyte = (check_sum >> 4) & 0x0F;
        
        if (hbyte < 10)
            syncClockStr[len] = hbyte + '0';
        else
            syncClockStr[len] = (hbyte - 10) + 'A';
        
        if (lbyte < 10)
            syncClockStr[len + 1] = lbyte + '0';
        else
            syncClockStr[len + 1] = (lbyte - 10) + 'A';   

        syncClockStr[len + 2] = 0;
        
        vbb_USART_Print(&(meter.usart_meter), syncClockStr);
    }    
}

void vbb_METER_Flush(void)
{
    uint8_t c;
    
    VBB_DAT_Queue * queue = &(meter.usart_meter.rBuffer);            
    
    deltaPulse = sensor.CollectedPulse - last_PulseCollected;
    last_PulseCollected = sensor.CollectedPulse;    

    if (vbb_RTC_GetSec() - LastSyncClock > 10 * 60)
    {
        METER_PushSyncClock();
        LastSyncClock = 
    }
    
    while (queue->head < queue->tail)
    {
        c = queue->buffer[queue->head & queue->bufferSizeMinusOne];
        queue->head++;                      

        if (meter.message.length == 0 && c == 'T') // Dong ho TC
        {
            meter_TC_detected = TRUE;
            meter_HP_detected = FALSE;
            
            METER_AddToMessage(c);
            _checksum = 0 + c;            
        }
        else if (meter.message.length == 0 && c == 'B') // Dong ho HP
        {
            meter_TC_detected = FALSE;
            meter_HP_detected = TRUE;
            
            METER_AddToMessage(c);
            _checksum = 0 + c;            
        }
        else if (meter.message.length == 2 && c == 'C' && meter_TC_detected)
        {
            METER_AddToMessage(c);
            _checksum = _checksum + c;
        }
        else if (meter.message.length == 2 && c == 'A' && meter_HP_detected)
        {
            METER_AddToMessage(c);
            _checksum = _checksum + c;
        }
        else if (meter.message.length == 4 && ((c >= '0' && c <= '9') || c == 'A'))
        {
            METER_AddToMessage(c);
            _checksum = _checksum + c;
            
            _curMsg = c;
            
            switch (c)
            {
                case '1':
                case '2':
                case '3':                    
                case '4':
                case '5':
                {
                    if (meter_TC_detected)
                        remainLength = 31;
                    else if (meter_HP_detected)
                        remainLength = 22;                        
                    break;
                }

                case '6':
                {
                    if (meter_TC_detected)
                        remainLength = 7;
                    else if (meter_HP_detected)
                        remainLength = 7;
                    break;
                }

                case '7':
                {
                    if (meter_TC_detected)
                        remainLength = 43;
                    else if (meter_HP_detected)
                        remainLength = 37;
                    break;
                }

                case '8':
                {
                    if (meter_TC_detected)
                        remainLength = 42;
                    else if (meter_HP_detected)
                        remainLength = 36;
                    break;
                }

                case '9':
                {
                    if (meter_TC_detected)
                        remainLength = 65;
                    else if (meter_HP_detected)
                        remainLength = 41;
                    break;
                }
                
                case 'A':
                {
                    if (meter_TC_detected)
                        remainLength = 29;
                    else if (meter_HP_detected)                        
                        remainLength = 24;
                    break;
                }      
            }
        }
        else if (meter.message.length > 4 && remainLength > 0)
        {     
            METER_AddToMessage(c);
            
            remainLength--;
            
            if (remainLength > 0)
                _checksum = _checksum + c;  
            else if (remainLength == 0) // 2013.09.27 Remember to check the checksum for valid message
            {   
                /*
                if (_curMsg == '1')
                    METER_OnTaxiTrip();
                else if (_curMsg == '3')
                    METER_OffTaxiTrip();
                */
                
                if (_curMsg >= '1' && _curMsg <= '5')
                {                    
                    //2013.10.02 Reduce the number of '3' and '1' message
                    if (_curMsg == '3' || _curMsg == '1')                        
                    {
                        if (_curMsg == '1')
                            cab_occupied = FALSE;
                        else
                            cab_occupied = TRUE;
                        
                        if (vbb_RTC_GetSec() - LastSendSecondlyMessage > 30)
                        {
                            LastSendSecondlyMessage = vbb_RTC_GetSec();
                            vbb_FLASHMEM_PushMessageF("$METER,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,INFO,%s",
                            VERSION,
                            storage.config.OwnerId,
                            storage.config.VehicleId,                                
                            rtc.hour,
                            rtc.minute,
                            rtc.second,
                            rtc.day,                
                            rtc.month,
                            rtc.year % 100,
                            meter.message.buff);
                        }
                    }
                    else
                    {
                        vbb_FLASHMEM_PushMessageF("$METER,%d,%s,%s,%02d%02d%02d,%02d%02d%02d,INFO,%s",
                            VERSION,
                            storage.config.OwnerId,
                            storage.config.VehicleId,                                
                            rtc.hour,
                            rtc.minute,
                            rtc.second,
                            rtc.day,                
                            rtc.month,
                            rtc.year % 100,
                            meter.message.buff);
                    }
                }                                     
                
                vbb_Message_Init(&(meter.message));
            }
        }
        else
        {
            vbb_Message_Init(&(meter.message)); //invalid format then clear everything
        }
    }
    
    if (!meter_HP_detected && !meter_TC_detected)
    {
        if (vbb_PIN_Get(&(sensor.pin_door)))
            METER_OnTaxiTrip();
        else
            METER_OffTaxiTrip();
    }
    
    if (!cab_occupied)
        free_PulseCount += deltaPulse;
    else
        busy_PulseCount += deltaPulse;
    
    vbb_BACKUP_SetInt(SAVE_METER_FREE_PULSE, free_PulseCount);
    vbb_BACKUP_SetInt(SAVE_METER_BUSY_PULSE, busy_PulseCount);
}



#endif
